package org.antlr.generated;

import com.gbase8c.dmt.model.migration.dto.FunctionDto;
import com.google.common.collect.Lists;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.misc.Interval;

import java.util.List;
import java.util.stream.Collectors;

public class FunctionVisitorImpl extends FunctionBaseVisitor<Object> {

    protected FunctionDto dto;

    public FunctionDto getFunctionDto() {
        return dto;
    }

    @Override
    public Object visitProg(FunctionParser.ProgContext ctx) {
        return super.visitProg(ctx);
    }

    @Override
    public Object visitFunction(FunctionParser.FunctionContext ctx) {
        dto = FunctionDto.builder().build();
        return super.visitFunction(ctx);
    }

    @Override
    public Object visitFunctionName(FunctionParser.FunctionNameContext ctx) {
        String name = ctx.Identifier().getText();
        dto.setName(name);
        return name;
    }

    @Override
    public Object visitParameters(FunctionParser.ParametersContext ctx) {
        List<FunctionDto.Parameter> parameters = ctx.parameter().stream()
                .map(this::visit)
                .map(obj -> (FunctionDto.Parameter) obj)
                .collect(Collectors.toList());
        dto.setParamDtos(parameters);
        return parameters;
    }

    @Override
    public Object visitParameter(FunctionParser.ParameterContext ctx) {
        List<FunctionDto.Mode> modes = Lists.newArrayList();
        if (ctx.modes() != null) {
            modes = (List<FunctionDto.Mode>) visit(ctx.modes());
        }
        FunctionDto.Parameter parameter = FunctionDto.Parameter.builder()
                .paramName(ctx.Identifier().getText())
                .modes(modes)
                .build();
        parameter.setSrcType(ctx.dataType().getText());
        return parameter;
    }

    @Override
    public Object visitModes(FunctionParser.ModesContext ctx) {
        List<FunctionDto.Mode> modes = Lists.newArrayList();
        if (ctx.getText() != null) {
            String text = ctx.getText();
            if (text.contains("IN")) {
                modes.add(FunctionDto.Mode.IN);
            }
            if (text.contains("OUT")) {
                modes.add(FunctionDto.Mode.OUT);
            }
        }
        return modes;
    }

    @Override
    public Object visitDataType(FunctionParser.DataTypeContext ctx) {
        return ctx.getText();
    }

    @Override
    public Object visitReturnDataType(FunctionParser.ReturnDataTypeContext ctx) {
        String srcType = ctx.dataType().getText();
        dto.setSrcType(srcType);
        return srcType;
    }

    @Override
    public Object visitVariables(FunctionParser.VariablesContext ctx) {
        List<FunctionDto.Variable> variables = ctx.variable().stream()
                .map(this::visit)
                .map(obj -> (FunctionDto.Variable) obj)
                .collect(Collectors.toList());
        dto.setVarDtos(variables);
        return variables;
    }

    @Override
    public Object visitVariable(FunctionParser.VariableContext ctx) {
        FunctionDto.Variable variable = FunctionDto.Variable.builder()
                .varName(ctx.Identifier().getText())
                .build();
        variable.setSrcType(ctx.dataType().getText());
        return variable;
    }

    @Override
    public Object visitFunctionBody(FunctionParser.FunctionBodyContext ctx) {
        String functionBody = getFullText(ctx);
        dto.setSrcFunctionBody(functionBody);
        return functionBody;
    }

    public String getFullText(ParserRuleContext ctx) {
        if (ctx.children == null) {
            return "";
        }
        int startIndex = ctx.getStart().getStartIndex();
        int stopIndex = ctx.getStop().getStopIndex();
        Interval interval = new Interval(startIndex, stopIndex);
        return ctx.start.getInputStream().getText(interval);
    }

//    @Override
//    public Object visitReturnExpression(FunctionParser.ReturnExpressionContext ctx) {
//        String returnExpression = ctx.expression().getText();
//        dto.setReturnExpression(returnExpression);
//        return returnExpression;
//    }

    @Override
    public Object visitPrimaryExpression(FunctionParser.PrimaryExpressionContext ctx) {
        return super.visitPrimaryExpression(ctx);
    }

    @Override
    public Object visitArrayExpression(FunctionParser.ArrayExpressionContext ctx) {
        return super.visitArrayExpression(ctx);
    }

    @Override
    public Object visitShiftExpression(FunctionParser.ShiftExpressionContext ctx) {
        return super.visitShiftExpression(ctx);
    }

    @Override
    public Object visitAdditiveExpression(FunctionParser.AdditiveExpressionContext ctx) {
        return super.visitAdditiveExpression(ctx);
    }

    @Override
    public Object visitRelationalExpression(FunctionParser.RelationalExpressionContext ctx) {
        return super.visitRelationalExpression(ctx);
    }

    @Override
    public Object visitInclusiveOrExpression(FunctionParser.InclusiveOrExpressionContext ctx) {
        return super.visitInclusiveOrExpression(ctx);
    }

    @Override
    public Object visitConditionalExpression(FunctionParser.ConditionalExpressionContext ctx) {
        return super.visitConditionalExpression(ctx);
    }

    @Override
    public Object visitMultiplicativeExpression(FunctionParser.MultiplicativeExpressionContext ctx) {
        return super.visitMultiplicativeExpression(ctx);
    }

    @Override
    public Object visitConditionalAndExpression(FunctionParser.ConditionalAndExpressionContext ctx) {
        return super.visitConditionalAndExpression(ctx);
    }

    @Override
    public Object visitPostExpression(FunctionParser.PostExpressionContext ctx) {
        return super.visitPostExpression(ctx);
    }

    @Override
    public Object visitCustomExpression(FunctionParser.CustomExpressionContext ctx) {
        return super.visitCustomExpression(ctx);
    }

    @Override
    public Object visitUnaryExpressionNotPlusMinus(FunctionParser.UnaryExpressionNotPlusMinusContext ctx) {
        return super.visitUnaryExpressionNotPlusMinus(ctx);
    }

    @Override
    public Object visitAndExpression(FunctionParser.AndExpressionContext ctx) {
        return super.visitAndExpression(ctx);
    }

    @Override
    public Object visitArrayAccessExpression(FunctionParser.ArrayAccessExpressionContext ctx) {
        return super.visitArrayAccessExpression(ctx);
    }

    @Override
    public Object visitConditionalOrExpression(FunctionParser.ConditionalOrExpressionContext ctx) {
        return super.visitConditionalOrExpression(ctx);
    }

    @Override
    public Object visitExclusiveOrExpression(FunctionParser.ExclusiveOrExpressionContext ctx) {
        return super.visitExclusiveOrExpression(ctx);
    }

    @Override
    public Object visitEqualityExpression(FunctionParser.EqualityExpressionContext ctx) {
        return super.visitEqualityExpression(ctx);
    }

    @Override
    public Object visitUnaryExpression(FunctionParser.UnaryExpressionContext ctx) {
        return super.visitUnaryExpression(ctx);
    }

    @Override
    public Object visitParentExpression(FunctionParser.ParentExpressionContext ctx) {
        return super.visitParentExpression(ctx);
    }

    @Override
    public Object visitLiteralExpression(FunctionParser.LiteralExpressionContext ctx) {
        return super.visitLiteralExpression(ctx);
    }

    @Override
    public Object visitIdentifierExpression(FunctionParser.IdentifierExpressionContext ctx) {
        return super.visitIdentifierExpression(ctx);
    }

    @Override
    public Object visitIntegerExpression(FunctionParser.IntegerExpressionContext ctx) {
        return super.visitIntegerExpression(ctx);
    }

    @Override
    public Object visitFloatExpression(FunctionParser.FloatExpressionContext ctx) {
        return super.visitFloatExpression(ctx);
    }

    @Override
    public Object visitCharacterExpression(FunctionParser.CharacterExpressionContext ctx) {
        return super.visitCharacterExpression(ctx);
    }

    @Override
    public Object visitStringExpression(FunctionParser.StringExpressionContext ctx) {
        return super.visitStringExpression(ctx);
    }

    @Override
    public Object visitBooleanExpresion(FunctionParser.BooleanExpresionContext ctx) {
        return super.visitBooleanExpresion(ctx);
    }

    @Override
    public Object visitNullExpression(FunctionParser.NullExpressionContext ctx) {
        return super.visitNullExpression(ctx);
    }
}
